package com.mobilereports.model;

import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import com.mobilereports.service.ReportsService;
import com.mobilereports.sort.ValuesDescendingComparator;

public class ReportChartModel extends ChartModel {

	private ReportsService reportService;
	private List<ReportColumn> hierarchy;
	private List<Sample> samplesPath = new LinkedList<Sample>();
	private Report report;
	private LinkedList<Sample> samples = new LinkedList<Sample>();
	private ReportColumn measureColumn;
	private ChartModelListener listener;
	
	public void setListener(ChartModelListener listener) {
		this.listener = listener;
	}

	public ReportChartModel(ReportsService reportService) {
		super();
		this.reportService = reportService;
	}
	
	public void setHierarchy(List<ReportColumn> hierarchy) {
		this.hierarchy = hierarchy;
	}

	public void setReport(Report report) {
		this.report = report;
	}
	
	public void setMeasureColumn(ReportColumn measureColumn) {
		this.measureColumn = measureColumn;
	}

	public synchronized void refreshReport() {
		String path = "null";
		if(!samplesPath.isEmpty()) {
			Sample last = samplesPath.get(samplesPath.size() - 1);
			path = last.getPath();
		}
		List<Record> records = this.reportService.fetchData(report, hierarchy, path);
		ReportColumn c = getCurrentColumn();
		
		LinkedList<Sample> newSamples = new LinkedList<Sample>();
		for(Record r: records) {
			Sample s = new Sample();
			
			s.setPath(r.getAttribute("path").toString());
			s.setLabel(r.getAttribute(c.getName()).toString());
			s.setValue(Double.parseDouble(r.getAttribute(measureColumn.getName()).toString()));
			
			newSamples.add(s);
		}
		Collections.sort(newSamples, new ValuesDescendingComparator());
		refreshSampleIndexMap(newSamples);
		Collections.sort(newSamples, getComparator());
		
		samples = newSamples;
		listener.onDataChanged();
	}
	
	private ReportColumn getCurrentColumn() {
		return this.hierarchy.get(samplesPath.size());
	}

	public void drillDown(Sample sample) {
		if(samplesPath.size() + 1 == hierarchy.size()) {
			return;
		}
		samplesPath.add(sample);
		refreshReport();
	}

	@Override
	public synchronized List<Sample> getSamples() {
		return Collections.unmodifiableList(samples);
	}

	@Override
	public void drillUp()
	{
		if(samplesPath.isEmpty())
			return;
		samplesPath.remove(samplesPath.size() - 1);
		refreshReport();
	}

	public ReportColumn getMeasureColumn()
	{
		return measureColumn;
	}
	
	public Map<Double, Integer> getSampleIndexMap() {
		return sampleIndexMap;
	}
	
	protected void refreshSampleIndexMap(List<Sample> newSamples) {
		sampleIndexMap.clear();
		for (int c1 = 0; c1 < newSamples.size(); c1++)
		{
			int index = getColorIndexBySequenceIndex(c1, newSamples);
			double value = newSamples.get(c1).getValue();
			if (!sampleIndexMap.containsKey(value) || index == 2)
				sampleIndexMap.put(value, index);
		}
	}
	
	private int getColorIndexBySequenceIndex(int seqIndex, List<Sample> newSamples)
	{
		if (newSamples.size() % 2 == 0)
		{
			if (seqIndex < newSamples.size() / 4)
				return 0;
			else if (seqIndex < newSamples.size() / 2)
				return 1;
			else if (seqIndex < 3 * newSamples.size() / 4)
				return 3;
			return 4;
		}
		else
		{
			if (seqIndex < newSamples.size() / 4)
				return 0;
			else if (seqIndex < newSamples.size() / 2)
				return 1;
			else if (seqIndex == newSamples.size() / 2)
				return 2;
			else if (seqIndex <= 3 * newSamples.size() / 4)
				return 3;
			return 4;
		}
	}
}
